#ifndef __CHANNEL_HPP__
#define __CHANNEL_HPP__

#include <functional>
#include <cstdint>
#include <sys/epoll.h>
class Poller; // 要用到，所以这里声明
class EventLoop;
class Channel
{
    using EventCallback = std::function<void()>;

public:
    Channel(int sockfd, EventLoop *loop) : _sockfd(sockfd), _loop(loop), _events(0), _revents(0),
                                          _read_callback(nullptr), _write_callback(nullptr),
                                          _error_callback(nullptr), _close_callback(nullptr), _event_callback(nullptr)
    {
    }

    /* 获取监控的文件描述符 */
    int Fd() const
    {
        return _sockfd;
    }

    /* 获取想要监控的事件 */
    uint32_t Events() const
    {
        return _events;
    }

    /* 设置就绪事件 */
    void SetREvents(const uint32_t events)
    {
        _revents = events;
    }

    /* 设置 可读事件被触发的回调函数 */
    void SetReadCallback(const EventCallback &cb)
    {
        _read_callback = cb;
    }
    /* 设置 可写事件被触发的回调函数 */
    void SetWriteCallback(const EventCallback &cb)
    {
        _write_callback = cb;
    }
    /* 设置 错误事件被触发的回调函数 */
    void SetErrorCallback(const EventCallback &cb)
    {
        _error_callback = cb;
    }
    /* 设置 连接关闭事件被触发的回调函数 */
    void SetCloseCallback(const EventCallback &cb)
    {
        _close_callback = cb;
    }
    /* 设置 任意事件被触发的回调函数 */
    void SetEventCallback(const EventCallback &cb)
    {
        _event_callback = cb;
    }

    /* 当前是否监控了可读事件 */
    bool ReadAble() const
    {
        return _events & EPOLLIN;
    }
    /* 当前是否监控了可写事件 */
    bool WriteAble() const
    {
        return _events & EPOLLOUT;
    }
    /* 打开对读事件的监控 */
    void EnableRead()
    {
        _events |= EPOLLIN;
        Update();
    }
    /* 打开对写事件的监控 */
    void EnableWrite()
    {
        _events |= EPOLLOUT;
        Update();
    }
    /* 关闭对读事件的监控 */
    void DisableRead()
    {
        _events &= ~EPOLLIN;
        Update();
    }
    /* 关闭对写事件的监控 */
    void DisableWrite()
    {
        _events &= ~EPOLLOUT;
        Update();
    }
    /* 关闭对所有事件的监控 */
    void DisableAll()
    {
        _events = 0;
        Update();
    }
    /* 移除监控——从EventLoop中移除需要监控的事件 */
    void Remove(); // 因为要用到Poller类的功能，但前面只是声明了Poller类，没有它的实现，所以该函数的实现也需要放到Poller类实现后
    /* 添加监控——存在则修改，不存在则添加 */
    void Update(); // 因为要用到Poller类的功能，但前面只是声明了Poller类，没有它的实现，所以该函数的实现也需要放到Poller类实现后
    /* 事件处理函数——只有有事件触发，就执行这个函数，在这个函数内部根据_revents再执行相对应的回调处理 */
    void HandleEvent()
    {
        if (_revents & (EPOLLIN | EPOLLRDHUP | EPOLLPRI))
        {
            if (_event_callback)
                _event_callback();// 事件处理可能会出错，出错可能会关闭连接，所以在事件处理之前刷新连接活跃度
            if (_read_callback)
                _read_callback();

            // 事件处理完毕后再调用任意事件的回调，如刷新活跃度，需要处理完再刷新
        }
        // 下面操作可能会释放连接，使用if-else分支
        if (_revents & EPOLLOUT)
        {
            if (_event_callback)
                _event_callback();// 事件处理可能会出错，出错可能会关闭连接，所以在事件处理之前刷新连接活跃度
            if (_write_callback)
                _write_callback();

            // 事件处理完毕后再调用任意事件的回调，如刷新活跃度，需要处理完再刷新
        }
        else if (_revents & EPOLLERR)
        {
            if (_event_callback)
                _event_callback();
            // 错误事件被触发会关闭连接，所以要在错误事件回调前调用任意事件的回调
            if (_error_callback)
                _error_callback();
        }
        else if (_revents & EPOLLHUP)
        {
            if (_event_callback)
                _event_callback();
            if (_close_callback)
                _close_callback();
        }
        // if(_event_callback) _event_callback();// TODO
    }

private:
    int _sockfd; // 对文件描述符上的事件进行监控
    EventLoop *_loop;
    uint32_t _events;  // 当前需要监控的事件
    uint32_t _revents; // 当前连接触发的事件

    EventCallback _read_callback;  // 可读事件被触发的回调函数
    EventCallback _write_callback; // 可写事件被触发的回调函数
    EventCallback _error_callback; // 错误事件被触发的回调函数
    EventCallback _close_callback; // 连接关闭事件被触发的回调函数
    EventCallback _event_callback; // 任意事件被触发的回调函数
};

#endif
